package com.stars.easyms.demo.rest.service.jdk8;

import com.stars.easyms.demo.rest.dto.output.jdk8.Jdk8Demo7Output;
import com.stars.easyms.rest.RestService;
import com.stars.easyms.base.util.MessageFormatUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>className: EasyMsJdk8Demo7Service</p>
 * <p>description: SimpleDateFormat和DateTimeFormatter比较的demo</p>
 *
 * @author guoguifang
 * @date 2019/8/21 17:05
 * @since 1.3.2
 */
@Slf4j
@Service
public class EasyMsJdk8Demo7Service implements RestService<Void, Jdk8Demo7Output> {

    private static final int TOTAL_COUNT = 500000;

    private static final int THREAD_COUNT = 50;

    private static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_PATTERN);

    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);

    private String[] dates = {"2019-01-01 12:00:00", "2019-02-01 12:00:00", "2019-03-01 12:00:00"};

    private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);

    @Override
    public Jdk8Demo7Output execute(Void input) {
        Jdk8Demo7Output output = new Jdk8Demo7Output();

        // 1.单线程format
        output.setSingleThreadFormat(singleThreadFormat());

        // 2.单线程parse
        output.setSingleThreadParse(singleThreadParse());

        // 3.多线程format（不加锁）
        output.setMultiThreadFormatWithoutLock(multiThreadFormatWithoutLock());

        // 4.多线程parse（不加锁）
        output.setMultiThreadParseWithoutLock(multiThreadParseWithoutLock());

        // 5.多线程format（加锁）
        output.setMultiThreadFormatWithLock(multiThreadFormatWithLock());

        // 6.多线程parse（加锁）
        output.setMultiThreadParseWithLock(multiThreadParseWithLock());

        return null;
    }

    private String singleThreadFormat() {
        // 1.使用SimpleDateFormat的方式
        int simpleDateFormatExceptionCount = 0;
        long simpleDateFormatStartTime = System.currentTimeMillis();
        for (int i = 0; i < TOTAL_COUNT; i++) {
            try {
                simpleDateFormat.format(new Date());
            } catch (Exception e) {
                simpleDateFormatExceptionCount++;
            }
        }
        long simpleDateFormatEndTime = System.currentTimeMillis();

        // 2.使用DateTimeFormatter的方式
        int dateTimeFormatterExceptionCount = 0;
        long dateTimeFormatterStartTime = System.currentTimeMillis();
        for (int i = 0; i < TOTAL_COUNT; i++) {
            try {
                dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault()));
            } catch (Exception e) {
                dateTimeFormatterExceptionCount++;
            }
        }
        long dateTimeFormatterEndTime = System.currentTimeMillis();

        return MessageFormatUtil.format("单线程format用时比较(SimpleDateFormat用时{}ms, DateTimeFormatter用时{}ms), " +
                        "单线程format错误数量比较(SimpleDateFormat错误{}次, DateTimeFormatter错误{}次)",
                simpleDateFormatEndTime - simpleDateFormatStartTime, dateTimeFormatterEndTime - dateTimeFormatterStartTime,
                simpleDateFormatExceptionCount, dateTimeFormatterExceptionCount);
    }

    private String singleThreadParse() {
        // 1.使用SimpleDateFormat的方式
        int simpleDateFormatExceptionCount = 0;
        long simpleDateFormatStartTime = System.currentTimeMillis();
        for (int i = 0; i < TOTAL_COUNT; i++) {
            try {
                simpleDateFormat.parse(dates[i % 3]);
            } catch (Exception e) {
                simpleDateFormatExceptionCount++;
            }
        }
        long simpleDateFormatEndTime = System.currentTimeMillis();

        // 2.使用DateTimeFormatter的方式
        int dateTimeFormatterExceptionCount = 0;
        long dateTimeFormatterStartTime = System.currentTimeMillis();
        for (int i = 0; i < TOTAL_COUNT; i++) {
            try {
                LocalDateTime.parse(dates[i % 3], dateTimeFormatter);
            } catch (Exception e) {
                dateTimeFormatterExceptionCount++;
            }
        }
        long dateTimeFormatterEndTime = System.currentTimeMillis();

        return MessageFormatUtil.format("单线程parse用时比较(SimpleDateFormat用时{}ms, DateTimeFormatter用时{}ms), " +
                        "单线程parse错误数量比较(SimpleDateFormat错误{}次, DateTimeFormatter错误{}次)",
                simpleDateFormatEndTime - simpleDateFormatStartTime, dateTimeFormatterEndTime - dateTimeFormatterStartTime,
                simpleDateFormatExceptionCount, dateTimeFormatterExceptionCount);
    }

    /**
     * 多线程不加锁情况（因为SimpleDateFormat是线程不安全的）
     */
    private String multiThreadFormatWithoutLock() {
        List<Future> futureList = new ArrayList<>();

        // 1.使用SimpleDateFormat的方式
        AtomicInteger simpleDateFormatExceptionCount = new AtomicInteger();
        long simpleDateFormatStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        simpleDateFormat.format(new Date());
                    } catch (Exception e) {
                        simpleDateFormatExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // ingore
            }
        });
        long simpleDateFormatEndTime = System.currentTimeMillis();

        futureList.clear();

        // 2.使用DateTimeFormatter的方式
        AtomicInteger dateTimeFormatterExceptionCount = new AtomicInteger();
        long dateTimeFormatterStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault()));
                    } catch (Exception e) {
                        dateTimeFormatterExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // ingore
            }
        });
        long dateTimeFormatterEndTime = System.currentTimeMillis();

        return MessageFormatUtil.format("多线程不加锁format比较(SimpleDateFormat用时{}ms, DateTimeFormatter用时{}ms), " +
                        "多线程不加锁format错误数量比较(SimpleDateFormat错误{}次, DateTimeFormatter错误{}次)",
                simpleDateFormatEndTime - simpleDateFormatStartTime, dateTimeFormatterEndTime - dateTimeFormatterStartTime,
                simpleDateFormatExceptionCount.get(), dateTimeFormatterExceptionCount.get());
    }

    /**
     * 多线程不加锁情况（因为SimpleDateFormat是线程不安全的）
     */
    private String multiThreadParseWithoutLock() {
        List<Future> futureList = new ArrayList<>();

        // 1.使用SimpleDateFormat的方式
        AtomicInteger simpleDateFormatExceptionCount = new AtomicInteger();
        long simpleDateFormatStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        simpleDateFormat.parse(dates[j % 3]);
                    } catch (Exception e) {
                        simpleDateFormatExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // ingore
            }
        });
        long simpleDateFormatEndTime = System.currentTimeMillis();

        futureList.clear();

        // 2.使用DateTimeFormatter的方式
        AtomicInteger dateTimeFormatterExceptionCount = new AtomicInteger();
        long dateTimeFormatterStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        LocalDateTime.parse(dates[j % 3], dateTimeFormatter);
                    } catch (Exception e) {
                        dateTimeFormatterExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // ingore
            }
        });
        long dateTimeFormatterEndTime = System.currentTimeMillis();

        return MessageFormatUtil.format("多线程不加锁parse比较(SimpleDateFormat用时{}ms, DateTimeFormatter用时{}ms), " +
                        "多线程不加锁parse错误数量比较(SimpleDateFormat错误{}次, DateTimeFormatter错误{}次)",
                simpleDateFormatEndTime - simpleDateFormatStartTime, dateTimeFormatterEndTime - dateTimeFormatterStartTime,
                simpleDateFormatExceptionCount.get(), dateTimeFormatterExceptionCount.get());
    }

    /**
     * 多线程不加锁情况（因为SimpleDateFormat是线程不安全的，有时候为了避免异常而需要加锁）
     */
    private String multiThreadFormatWithLock() {
        List<Future> futureList = new ArrayList<>();

        // 1.使用SimpleDateFormat的方式
        AtomicInteger simpleDateFormatExceptionCount = new AtomicInteger();
        long simpleDateFormatStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    synchronized (this) {
                        try {
                            simpleDateFormat.format(new Date());
                        } catch (Exception e) {
                            simpleDateFormatExceptionCount.incrementAndGet();
                        }
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        long simpleDateFormatEndTime = System.currentTimeMillis();

        futureList.clear();

        // 2.使用DateTimeFormatter的方式(线程安全不需要加锁)
        AtomicInteger dateTimeFormatterExceptionCount = new AtomicInteger();
        long dateTimeFormatterStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault()));
                    } catch (Exception e) {
                        dateTimeFormatterExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        long dateTimeFormatterEndTime = System.currentTimeMillis();

        return MessageFormatUtil.format("多线程加锁format比较(SimpleDateFormat用时{}ms, DateTimeFormatter用时{}ms), " +
                        "多线程加锁format错误数量比较(SimpleDateFormat错误{}次, DateTimeFormatter错误{}次)",
                simpleDateFormatEndTime - simpleDateFormatStartTime, dateTimeFormatterEndTime - dateTimeFormatterStartTime,
                simpleDateFormatExceptionCount.get(), dateTimeFormatterExceptionCount.get());
    }

    /**
     * 多线程不加锁情况（因为SimpleDateFormat是线程不安全的）
     */
    private String multiThreadParseWithLock() {
        List<Future> futureList = new ArrayList<>();

        // 1.使用SimpleDateFormat的方式
        AtomicInteger simpleDateFormatExceptionCount = new AtomicInteger();
        long simpleDateFormatStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        synchronized (this) {
                            simpleDateFormat.parse(dates[j % 3]);
                        }
                    } catch (Exception e) {
                        simpleDateFormatExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // ingore
            }
        });
        long simpleDateFormatEndTime = System.currentTimeMillis();

        futureList.clear();

        // 2.使用DateTimeFormatter的方式
        AtomicInteger dateTimeFormatterExceptionCount = new AtomicInteger();
        long dateTimeFormatterStartTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            futureList.add(executorService.submit(() -> {
                for (int j = 0; j < TOTAL_COUNT; j++) {
                    try {
                        LocalDateTime.parse(dates[j % 3], dateTimeFormatter);
                    } catch (Exception e) {
                        dateTimeFormatterExceptionCount.incrementAndGet();
                    }
                }
                return 0;
            }));
        }
        futureList.forEach(future -> {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                // ingore
            }
        });
        long dateTimeFormatterEndTime = System.currentTimeMillis();

        return MessageFormatUtil.format("多线程加锁parse比较(SimpleDateFormat用时{}ms, DateTimeFormatter用时{}ms), " +
                        "多线程加锁parse错误数量比较(SimpleDateFormat错误{}次, DateTimeFormatter错误{}次)",
                simpleDateFormatEndTime - simpleDateFormatStartTime, dateTimeFormatterEndTime - dateTimeFormatterStartTime,
                simpleDateFormatExceptionCount.get(), dateTimeFormatterExceptionCount.get());
    }

}